package mylittleinvestigations.GameUi;

import mylittleinvestigations.GameUi.Arrow;
import mylittleinvestigations.GameUi.ArrowDirection;
import java.util.*;
import mylittleinvestigations.Events.ButtonArrayEventProvider;
import mylittleinvestigations.Events.ButtonEventProvider;
import mylittleinvestigations.Events.ButtonEventListener;
import mylittleinvestigations.PersistentThreads.RenderThread;
import mylittleinvestigations.Settings;
import mylittleinvestigations.Vector2;
import org.newdawn.slick.*;
import org.newdawn.slick.geom.*;

public class ButtonArray implements ButtonEventListener
{
    private static final int ButtonCascadeDelay = 125;
    private static final int TextHeight = 29;

    private static Rectangle dialogRect;
    private static int desiredPadding;
    //private static Image promptTexture;
    //private static Rectangle promptRect;
    //private static UnicodeFont headerFont;
    private static UnicodeFont textFont;

    //private static Arrow leftArrow;
    //private static Arrow rightArrow;

    private ArrayList<Button> buttonList;
    private boolean buttonClicked;
    private int topButtonIndex;
    //private String headerText;
    private Tab backTab;

    private Button topButton;
    private Button bottomButton;
    private Arrow upArrow;
    private Arrow downArrow;

    private boolean isCancelable;

    public boolean getIsCancelable() { return this.isCancelable; }
    public void setIsCancelable(boolean isCancelable) { this.isCancelable = isCancelable; }

    public int getCount()
    {
        return this.buttonList.size();
    }

    public boolean getIsClosed()
    {
        return this.topButton.getIsHidden() && (this.bottomButton == null || this.bottomButton.getIsHidden());
    }

    public static void Initialize(int x, int y, int width, int height, int desiredPadding, Image promptTexture, UnicodeFont headerFont, UnicodeFont textFont)
    {
        ButtonArray.dialogRect = new Rectangle(x, y, width, height);
        ButtonArray.desiredPadding = desiredPadding;
        //ButtonArray.promptTexture = promptTexture;
        //ButtonArray.promptRect = new Rectangle(x + width / 2 - promptTexture.getWidth() / 2, y - promptTexture.getHeight(), promptTexture.getWidth(), promptTexture.getHeight());
        //ButtonArray.headerFont = headerFont;
        ButtonArray.textFont = textFont;

        //ButtonArray.leftArrow = new Arrow((int)promptRect.getX() + 5, (int)promptRect.getY() + 4, ArrowDirection.Down, 10 /* bounceDistance */, false /* isClickable */);
        //ButtonArray.rightArrow = new Arrow((int)promptRect.getX() + (int)promptRect.getWidth() - 29, (int)promptRect.getY() + 4, ArrowDirection.Down, 10 /* bounceDistance */, false /* isClickable */);
    }

    public ButtonArray(String headerText)
    {
        this.buttonList = new ArrayList<Button>();
        //this.headerText = headerText;
        this.backTab = new Tab((int)Settings.DisplayBounds.getX() - Tab.Width, true /* isClickable */, "BACK", true /* isCancel */);
        this.isCancelable = false;
    }

    public void Load(List<ButtonArrayLoadParameters> loadParametersList)
    {
        this.Reset();

        for (int i = 0; i < loadParametersList.size(); i++)
        {
            ButtonArrayLoadParameters loadParameters = loadParametersList.get(i);
            
            Button button = new Button(i, loadParameters.text);

            if (loadParameters.isDisabled)
            {
                button.setIsDisabled(true);
            }
            else
            {
                button.setShowCheckMark(loadParameters.showCheckBox);
                button.setShowLock(loadParameters.showLock);
                button.setCustomIconId(loadParameters.customIconId);
            }

            this.buttonList.add(button);
        }
    }

    public void Show()
    {
        if (this.upArrow == null)
        {
            this.upArrow = new Arrow((int)dialogRect.getX() + (int)dialogRect.getWidth() / 2 - 12, (int)dialogRect.getY() + 10, ArrowDirection.Up, 10 /* bounceDistance */, true /* isClickable */);
            this.downArrow = new Arrow((int)dialogRect.getX() + (int)dialogRect.getWidth() / 2 - 12, (int)dialogRect.getY() + (int)dialogRect.getHeight() - 20 - 10, ArrowDirection.Down, 10 /* bounceDistance */, true /* isClickable */);
        }

        this.buttonClicked = false;

        // If there's a button with no checkmark next to it,
        // show that one initially.
        this.topButtonIndex = 0;

        for (int i = 0; i < this.buttonList.size(); i++)
        {
            if (!this.buttonList.get(i).getShowCheckMark())
            {
                this.topButtonIndex = i;
                break;
            }
        }

        this.UpdateButtons();
        ButtonEventProvider.RegisterListener(this);

        for (int i = 0; i < this.buttonList.size(); i++)
        {
            Button button = this.buttonList.get(i);

            if (button == this.topButton)
            {
                button.setInAnimationDelay(0);
                button.setOutAnimationDelay(0);
                button.Show();
            }
            else if (button == this.bottomButton)
            {
                button.setInAnimationDelay(ButtonCascadeDelay);
                button.setOutAnimationDelay(ButtonCascadeDelay);
                button.Show();
            }
            else
            {
                button.ShowInstantly();
            }
        }
    }

    public void Close()
    {
        ButtonEventProvider.ClearListener(this);
        this.topButton.Hide();

        if (this.bottomButton != null)
        {
            this.bottomButton.Hide();
        }
    }

    public void Update(GameContainer gc,int delta)
    {
        //leftArrow.Update(gc,delta);
        //rightArrow.Update(gc,delta);

        if (this.getIsCancelable() && !buttonClicked)
        {
            this.backTab.Update();

            if (this.backTab.getIsClicked())
            {
                this.OnCanceled();
            }
        }

        this.topButton.Update(gc,delta);

        if (this.bottomButton != null)
        {
            this.bottomButton.Update(gc,delta);
        }

        if (this.topButton.getIsReady() && this.bottomButton != null && this.bottomButton.getIsReady())
        {
            this.upArrow.Update(gc,delta);
            this.downArrow.Update(gc,delta);
        }

        if (this.upArrow.getIsClicked() || this.downArrow.getIsClicked())
        {
            if (this.upArrow.getIsClicked())
            {
                this.topButtonIndex--;
            }
            else
            {
                this.topButtonIndex++;
            }

            this.UpdateButtons();
        }
    }

    public void Draw(GameContainer gc, Graphics g)
    {
        this.Draw(gc, g, 0);
    }

    public void Draw(GameContainer gc, Graphics g, float yOffset)
    {
        /*Vector2 headerPosition =
            new Vector2(
                promptRect.getX() + promptRect.getWidth() / 2 - headerFont.getWidth(this.headerText) / 2,
                promptRect.getY() + 4);
        
        RenderThread.getInstance().AddImageToRenderQueue(promptTexture, promptRect.getX(), promptRect.getY());
        RenderThread.getInstance().AddStringToRenderQueue(headerFont, (float)headerPosition.getX(), (float)headerPosition.getY(), this.headerText);

        leftArrow.Draw(gc, g);
        rightArrow.Draw(gc, g);*/

        if (this.getIsCancelable())
        {
            this.backTab.Draw(gc, g, yOffset);
        }

        this.topButton.Draw(gc, g, yOffset);

        if (this.bottomButton != null)
        {
            this.bottomButton.Draw(gc, g, yOffset);
        }

        if (this.topButton.getIsReady() && this.bottomButton != null && this.bottomButton.getIsReady() && this.buttonList.size() > 2)
        {
            this.upArrow.Draw(gc, g, 0, yOffset);
            this.downArrow.Draw(gc, g, 0, yOffset);
        }
    }

    public void ReorderOutAnimations(int newFirstOutButtonId)
    {
        // If the bottom button doesn't even exist,
        // no sense worrying about animation order.
        if (this.bottomButton == null)
        {
            this.topButton.setOutAnimationDelay(0);
            return;
        }

        boolean topButtonFirstOut = false;

        if (newFirstOutButtonId == this.topButton.getId())
        {
            topButtonFirstOut = true;
        }
        else if (newFirstOutButtonId == this.bottomButton.getId())
        {
            topButtonFirstOut = false;
        }
        else
        {
            throw new IllegalStateException("Something very bad has happened - a button not being shown has been clicked!");
        }

        if (topButtonFirstOut)
        {
            this.topButton.setOutAnimationDelay(0);
            this.bottomButton.setOutAnimationDelay(ButtonCascadeDelay);
        }
        else
        {
            this.topButton.setOutAnimationDelay(ButtonCascadeDelay);
            this.bottomButton.setOutAnimationDelay(0);
        }
    }

    public void Reset()
    {
        //leftArrow.Reset();
        //rightArrow.Reset();
        this.backTab.Reset();
        this.buttonList.clear();
        this.buttonClicked = false;
    }

    private void UpdateButtons()
    {
        if (this.buttonList.size() == 1)
        {
            this.topButtonIndex = 0;
        }
        else if (this.topButtonIndex > this.buttonList.size() - 2)
        {
            this.topButtonIndex = this.buttonList.size() - 2;
        }

        if (this.buttonList.size() == 1)
        {
            this.topButton = this.buttonList.get(0);
            this.bottomButton = null;
        }
        else
        {
            this.topButton = this.buttonList.get(this.topButtonIndex);
            this.bottomButton = this.buttonList.get(this.topButtonIndex + 1);
        }

        int paddedX = (int)(dialogRect.getX() + desiredPadding);
        int paddedY = (int)(dialogRect.getY() + desiredPadding);
        int availableWidth = (int)(dialogRect.getWidth() - desiredPadding * 2);
        int availableHeight = (int)(dialogRect.getHeight() - desiredPadding * 2);

        if (this.bottomButton == null)
        {
            this.topButton.setXPosition(paddedX + availableWidth / 2 - (int)textFont.getWidth(this.topButton.getText()) / 2);
            this.topButton.setYPosition(paddedY + availableHeight / 2 - TextHeight / 2);
        }
        else
        {
            this.topButton.setXPosition(paddedX + availableWidth / 2 - (int)textFont.getWidth(this.topButton.getText()) / 2);
            this.topButton.setYPosition(paddedY + availableHeight / 2 - TextHeight / 2 - 3 * TextHeight / 4);

            this.bottomButton.setXPosition(paddedX + availableWidth / 2 - (int)textFont.getWidth(this.bottomButton.getText()) / 2);
            this.bottomButton.setYPosition(paddedY + availableHeight / 2 - TextHeight / 2 + 3 * TextHeight / 4);
        }

        this.upArrow.setIsEnabled(this.topButtonIndex > 0);
        this.downArrow.setIsEnabled(this.topButtonIndex < this.buttonList.size() - 2);
    }

    public void OnButtonClicked(Button button, int id)
    {
        ButtonArrayEventProvider.RaiseButtonClicked(this, id);
        this.buttonClicked = true;
    }

    private void OnCanceled()
    {
        ButtonArrayEventProvider.RaiseCanceled(this);
        this.buttonClicked = true;
    }
}
